﻿using Cofe.Core.Interfaces;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core.Service;
using Cofe.Core.EntryType;
using Cofe.Core.Utils;
using Cofe.Core.Dynamic;
using Cofe.Web;

namespace Cofe.Core.Property
{
    public class CofePropertyProvider : PropertyProviderBase<IPropertyHost>
    {
        #region Factory
        [Export(typeof(ICofeService))]
        [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
        public class Factory : ISecondaryPropertyProviderFactory
        {
            public IEnumerable<IPropertyProvider> GetSecoondaryPropertyProviders(IPropertyHost propertyHost)
            {
                if (!(propertyHost.SecondaryPropertyProviders.Any((p) => p is CofePropertyProvider)))
                    yield return new CofePropertyProvider(propertyHost) { _sl = ServiceLocater };
            }

            private IServiceLocater _serviceLocater = null;
            public IServiceLocater ServiceLocater
            {
                get { return _serviceLocater ?? CofeServices.ServiceLocater; }
                set { _serviceLocater = value; }
            }

        }
        #endregion




        #region Constructor

        private IServiceLocater _sl;
        private IEntryConstructor _ec { get { return _sl.FindService<IEntryConstructor>(); } }

        private IEntryTypeInfoManager _etim { get { return _sl.FindService<IEntryTypeInfoManager>(); } }

        public CofePropertyProvider(IPropertyHost propertyHost)
            : base(propertyHost, 
            Cofe.Core.PropertyDefinitions.CacheDefinitions,
            Cofe.Core.PropertyDefinitions.CofeDefinitions, Cofe.Core.PropertyDefinitions.CofeStreamDefinitions)
        {
            //registerAction<IEnumerable<XmlLink>>(CofeProperties.ListLinks,
            //    (pm) => listLink(pm));            

            registerProperties(CofeProperties.Name, () =>
                PathFE.GetFileName(Entity.Behaviors.GetProperty(CofeProperties.FullParseName).ValueAsString));

            registerProperties(CofeProperties.VolumeInfo, () =>
                {
                    string key, path;
                    string parseName = Entity.Behaviors.GetProperty<string>(CofeProperties.FullParseName);
                    PathFE.ParseFullParseName(parseName, out key, out path);
                    var vol = key != null ? CofeServices.VolumeRegistrar.LookupVolume(key) : null;
                    return vol != null ? vol.ToVolumeInfo() :
                        Cofe.Core.Implements.VolumeInfo.None;
                });

            registerProperties(CofeProperties.Label, () =>
                PathFE.GetFileName(Entity.Behaviors.GetProperty(CofeProperties.FullParseName).ValueAsString));

            //CofeAttributes ca = propertyHost.Behaviors.GetProperty(CofeProperties.CofeAttributes).ValueAs<CofeAttributes>();

            bool isDefInterfaceStrSupported = propertyHost.Behaviors.IsPropertySupported(CofeProperties.DefaultInterfaceTypeString);
            bool isDefInterfaceSupported = propertyHost.Behaviors.IsPropertySupported(CofeProperties.DefaultInterfaceType);
            bool isParentPathSupported = propertyHost.Behaviors.IsPropertySupported(CofeProperties.ParentParseName);
            bool isParentPPSupported = propertyHost.Behaviors.IsPropertySupported(CofeProperties.ParentPropertyProvider);
            bool isOpenReadStreamSupported = propertyHost.Behaviors.IsPropertySupported(CofeStreamProperties.OpenReadAsync);
            bool isOpenWriteStreamSupported = propertyHost.Behaviors.IsPropertySupported(CofeStreamProperties.OpenWriteAsync);



            if (isDefInterfaceStrSupported)
                registerProperties(CofeProperties.DefaultInterfaceType, () =>
                    {
                        var det = Entity.Behaviors.GetProperty<string>(CofeProperties.DefaultInterfaceTypeString);
                        if (Type.GetType(det) != null)
                            return Type.GetType(det);
                        foreach (var type in CofeServices.PropertyInterfaceManager.AllCastableInterfaces)
                            if (type.FullName == det)
                                return type;
                        return null;
                    });
            if (isDefInterfaceSupported)
                registerProperties(CofeProperties.DefaultInterfaceTypeString, () =>
                {
                    var det = Entity.Behaviors.GetProperty<Type>(CofeProperties.DefaultInterfaceType);
                    return det.FullName;
                });


            if (isParentPPSupported != isParentPathSupported) //either of them supported.
            {
                if (isParentPathSupported || isParentPPSupported)
                {
                    if (isParentPPSupported)
                        registerProperties(CofeProperties.Parent, () =>
                            {
                                var parentPP = Entity.Behaviors.GetProperty(CofeProperties.ParentPropertyProvider).ValueAs<IPropertyProvider>();
                                if (parentPP != null)
                                    return _ec.ConstructEntry<ICofeDirectoryInfo>(_ec.ConstructPropertyHost(parentPP));
                                else return null;
                            });

                    if (isParentPathSupported)
                        registerProperties(CofeProperties.Parent, () =>
                            {
                                string parentPath = Entity.Behaviors.GetProperty(CofeProperties.ParentParseName).ValueAsString;
                                if (String.IsNullOrEmpty(parentPath))
                                    return null;
                                else
                                    return _ec.ConstructEntryAsync<ICofeDirectoryInfo>(
                                        CofeServices.PathParserManager.Behaviors.TryParsePath(
                                           parentPath, ParsableType.ParsePathLookup)).Result;
                            });

                    registerProperties(CacheProperties.ParentId, () =>
                        {
                            return Entity.Behaviors.GetProperty<ICofeDirectoryInfo>(CofeProperties.Parent).Id;
                        });
                }

            }
            if (isOpenReadStreamSupported)
            {
                registerProperties(CofeStreamProperties.MD5, () =>
                    {
                        //Console.WriteLine("Getting MD5");
                        using (var sc = Entity.OpenStream(true, false))
                            return StreamUtils.GetMD5(sc.Stream);
                    });

                if (isOpenWriteStreamSupported)
                    registerProperties(CofeStreamProperties.Stream, () => Entity.OpenStream(true, false),
                        (pp) =>
                        {
                            using (var outputStream = Entity.OpenStream(false, true))
                                StreamUtils.CopyStream(pp.ValueAs<StreamContainer>().Stream, outputStream.Stream);
                            return true;
                        });
                else registerProperties(CofeStreamProperties.Stream, () => Entity.OpenStream(true, false));
            
            }

        }

        #endregion

        #region Methods


        //protected virtual IEnumerable<XmlLink> listLink(ParameterDic parameters)
        //{
        //    yield return new XmlLink(MediaType.Search, RelationType.List, new Uri("http://www.quickzip.org"));
        //}


        #endregion
    }
}
